package com.foxzzz.datamemory.service;

import com.alibaba.fastjson.JSON;
import com.foxzzz.datamemory.util.SpringContextUtil;
import com.foxzzz.datamemory.vo.EvParam;
import org.springframework.data.domain.*;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @Author wujie
 * @Class EvService
 * @Description
 * @Date 2020/5/27 9:21
 */
@Service
public class EvService {
    private Map<String, JpaRepository> repositoryHashMap = new HashMap<>();
    private Map<String, Class> entityMap = new HashMap<>();

    private JpaRepository findRepositoryByEntityName(String entityName) {
        //从缓存中获取
        JpaRepository repository = repositoryHashMap.get(entityName);
        if (repository != null) {
            return repository;
        }
        //从bean容器里面获取
        String fullClassName = String.format("com.foxzzz.datamemory.repository.%sRepository", entityName);

        try {
            Class clazz = Class.forName(fullClassName);
            JpaRepository jpaRepository = (JpaRepository) SpringContextUtil.getBean(clazz);
            repositoryHashMap.put(entityName, jpaRepository);
            return jpaRepository;
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    private Class findEntityClassByEntityName(String entityName) {
        Class clazz = entityMap.get(entityName);
        if (clazz != null) {
            return clazz;
        }
        String fullClassName = String.format("com.foxzzz.datamemory.entity.%s", entityName);
        try {
            clazz = Class.forName(fullClassName);
            entityMap.put(entityName, clazz);
            return clazz;
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    private Sort assembleOrder(List<Map<String, String>> sorts) {
        List<Sort.Order> orders = new LinkedList<>();
        for (Map<String, String> map : sorts) {
            for (Map.Entry<String, String> entry : map.entrySet()) {
                if (entry.getValue().toUpperCase().equals("DESC")) {
                    orders.add(Sort.Order.desc(entry.getKey()));
                } else {
                    orders.add(Sort.Order.asc(entry.getKey()));
                }
            }
        }
        return Sort.by(orders);
    }


    public List list(EvParam evParam) {
        String entityName = evParam.getEntityName();
        String exampleJson = evParam.getExampleJson();
        List<Map<String, String>> sorts = evParam.getSorts();
        if (exampleJson == null) {
            if (sorts == null || sorts.size() == 0) {
                return findRepositoryByEntityName(entityName).findAll();

            } else {
                return findRepositoryByEntityName(entityName).findAll(assembleOrder(sorts));
            }
        }
        Class entityClassByEntityName = findEntityClassByEntityName(entityName);
        Example<Object> of = Example.of(JSON.parseObject(exampleJson, entityClassByEntityName));
        if (sorts == null || sorts.size() == 0) {
            return findRepositoryByEntityName(entityName).findAll(of);
        } else {
            return findRepositoryByEntityName(entityName).findAll(of, assembleOrder(sorts));
        }
    }

    public Page page(EvParam evParam) {
        String entityName = evParam.getEntityName();
        String exampleJson = evParam.getExampleJson();
        List<Map<String, String>> sorts = evParam.getSorts();
        PageRequest pageRequest = null;
        Integer size = Optional.ofNullable(evParam.getSize()).orElse(10);
        Integer page = Optional.ofNullable(evParam.getPage()).orElse(0);
        if (sorts == null || sorts.size() == 0) {
            pageRequest = PageRequest.of(page, size);
        } else {
            pageRequest = PageRequest.of(page, size, assembleOrder(sorts));
        }
        if (exampleJson == null) {
            return findRepositoryByEntityName(entityName).findAll(pageRequest);
        } else {
            Class entityClassByEntityName = findEntityClassByEntityName(entityName);
            Example<Object> of = Example.of(JSON.parseObject(exampleJson, entityClassByEntityName));
            return findRepositoryByEntityName(entityName).findAll(of, pageRequest);
        }
    }

    public Object save(EvParam evParam) {
        String entityName = evParam.getEntityName();
        String exampleJson = evParam.getExampleJson();
        Class entityClassByEntityName = findEntityClassByEntityName(entityName);
        Object object = JSON.parseObject(exampleJson, entityClassByEntityName);
        return findRepositoryByEntityName(entityName).save(object);
    }

    public Object getById(String entityName, String id) {
        return findRepositoryByEntityName(entityName).findById(id).orElse(null);
    }

    public void deleteById(String entityName, String id) {
        findRepositoryByEntityName(entityName).deleteById(id);
    }

}
